﻿using System;
using System.Configuration;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Discovery;
using EasyComm.Contracts;
using EasyComm.Hosting.Configuration;
using EasyComm.SDK.Configuration;
using EasyComm.ServiceUnit;
using EasyComm.Utilities;

namespace EasyComm.SDK.Internal
{
    internal class ServiceContext
    {
        internal static AdminServiceUnit<IAdminNLBContract> GetAdminService(bool readFromConfig = true)
        {
            string configUrl = readFromConfig ? ConfigurationManager.AppSettings["NLBAdminServiceUrl"] : null;
            if (!string.IsNullOrWhiteSpace(configUrl))
            {
                Uri url = new Uri(configUrl);
                if (NetUtils.TCPOnlineCheck(url.Host, url.Port))
                {
                    Binding binding = GenericConfiguration.GetMainBinding();
                    return new AdminServiceUnit<IAdminNLBContract>(null) { Host = url.DnsSafeHost, Port = url.Port, ListenUri = url, Status = ServiceStatus.Online, Type = AdminServiceType.NLBAdmin };// AdminNLBProxy(binding, new EndpointAddress(configUrl));
                }
            }
            EasyCommContext.OnLog(null, MessageType.Info, "Trying to discover NLB admin service...");
            AdminServiceUnit<IAdminNLBContract> adminService = null;
            DiscoveryClient discoveryClient = null;
            try
            {
                Binding binding = GenericConfiguration.GetMainBinding();
                DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(binding, new EndpointAddress(NetUtils.GetAvailableLocalEndPoint("NLBDiscovery", "", ProtocolScheme.Tcp)));
                discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());

                FindCriteria proxyCriteria = new FindCriteria();
                if (ServiceConfiguration.OnlineCheckTimeout > 0)
                {
                    proxyCriteria.Duration = new TimeSpan(0, 0, ServiceConfiguration.OnlineCheckTimeout);
                }
                var results = discoveryClient.Find(proxyCriteria);

                foreach (EndpointDiscoveryMetadata endpoint in results.Endpoints)
                {
                    if (endpoint.ContractTypeNames.Count(item => item.Name == "IAdminNLBContract") > 0)
                    {
                        adminService = new AdminServiceUnit<IAdminNLBContract>(null) { Host = endpoint.Address.Uri.DnsSafeHost, Port = endpoint.Address.Uri.Port, ListenUri = endpoint.Address.Uri, Status = ServiceStatus.Online, Type = AdminServiceType.NLBAdmin };//new AdminNLBProxy(binding, endpoint.Address);

                        //save to config
                        System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                        KeyValueConfigurationElement endPointUrl = config.AppSettings.Settings["NLBAdminServiceUrl"];
                        if (endPointUrl == null)
                        {
                            config.AppSettings.Settings.Add("NLBAdminServiceUrl", endpoint.Address.Uri.ToString());
                        }
                        else
                        {
                            endPointUrl.Value = endpoint.Address.Uri.ToString();
                        }
                        config.Save(ConfigurationSaveMode.Full);
                        ConfigurationManager.RefreshSection("appSettings");

                        //EasyCommContext.OnLog(null, MessageType.Info, string.Format("NLB Admin service listening on {0}.", endpoint.Address.Uri));
                    }
                }
            }
            finally
            {
                if (discoveryClient != null)
                {
                    discoveryClient.Close();
                }
            }
            if (adminService == null)
            {
                return new AdminServiceUnit<IAdminNLBContract>(null) { Host = null, Port = 0, ListenUri = null, Status = ServiceStatus.NA, Type = AdminServiceType.NLBAdmin };
                //EasyCommContext.OnLog(null, MessageType.Warn, "No NLB admin service was found.");
            }
            return adminService;
        }
    }
}
